<?php
declare (strict_types=1);

namespace app\command;

use app\admin\model\collect\CollectResult;
use app\admin\model\collect\CollectRule;
use app\admin\model\collect\CollectTask;
use app\admin\util\CollectUtil;
use think\console\Command;
use think\console\Input;
use think\console\Output;
use Exception;
class CollectTaskCommand extends Command
{
    protected function configure()
    {
        // 指令配置
        $this->setName('collect_task')
            ->setDescription('执行采集命令');
    }

    protected function execute(Input $input, Output $output)
    {
        //将采集时间过长的任务标记为失败
        CollectTask::where("status", RUNNING)
            ->where("update_time","<",date("Y-m-d H:i:s",strtotime("-1 day")))
            ->update(["status"=>TIME_OUT]);
        $task = CollectTask::where("status", READY)->order('type')->findOrEmpty();
        if ($task->type == TASK_TYPE_SIMPLE) {
            $this->add_collect_task_type1($task);
        }elseif($task->type == TASK_TYPE_INCREASING){
            $this->add_collect_task_type2($task);
        }elseif($task->type == TASK_TYPE_AGAIN){
            $this->add_collect_task_type3($task);
        }
        $this->deal_collect_result($task);
        // 指令输出
        $output->writeln('任务执行结束!');
    }

    protected function test(){
        $collectRule=CollectRule::find(3);
        $collectResult=CollectResult::find(5);
            $collectResult->save(['status'=>2]);
            try{
                $result=CollectUtil::collect($collectResult->url,$collectRule);
                if($result){
                    $update=[
                        'status'=>3,
                        'short_result'=>$this->get_short_result($collectResult->type,$result),
                        'result'=>json_encode($result)
                    ];
                }else{
                    $update=['status'=>4];
                }
            }catch (Exception $e){
                echo $e->getMessage();
                $update=['status'=>5];
            }
            $collectResult->save($update);

    }
    protected function deal_collect_result($task)
    {
        CollectTask::where("id", $task->id)->update(["status"=>RUNNING]);
        $all_success=true;
        $error=true;
        $collectRule=CollectRule::find($task->collect_rule_id);
        foreach(CollectResult::where(['status'=>READY,"collect_task_id"=>$task->id])->cursor() as $collectResult){
            $collectResult->save(['status'=>RUNNING]);
            try{
                $result=CollectUtil::collect($collectResult->url,$collectRule);
                if($result){
                    $update=[
                        'status'=>SUCCESS,
                        'short_result'=>$this->get_short_result($collectRule->type,$result),
                        'result'=>json_encode($result)
                    ];
                    $error=false;
                }else{
                    $update=['status'=>ERROR];
                    $all_success=false;
                }
            }catch (Exception $e){
                echo $e->getMessage();
                $update=['status'=>TIME_OUT];
                $all_success=false;
            }
            $collectResult->save($update);
        }
        if($error){
            $status=ERROR;
        }else if(!$all_success&&!$error){
            $status=PART_SUCCESS;
        }else if($all_success){
            $status=SUCCESS;
        }
        CollectTask::where("id", $task->id)->update(["status"=>$status]);
    }

    protected function add_collect_task_type1($task){
        $urls = explode("\n", $task['urls']);
        foreach ($urls as $url) {
            $collectResult=CollectResult::where(["collect_task_id"=>$task->id,'url'=>$url])->findOrEmpty();
            if($collectResult->isEmpty()){
                $collectResult->save([
                    'collect_task_id' => $task->id,
                    'url' => $url,
                    'status' => READY
                ]);
            }
            if($collectResult->status!=SUCCESS){
                $task->save(['status'=>READY]);
            }
        }
    }
    protected function add_collect_task_type2($task){
        for($i=$task->matching_start;$i<=$task->matching_end;$i++){
            $url=str_replace('{i}',$i,$task->matching);
            $collectResult=CollectResult::where(["collect_task_id"=>$task->id,'url'=>$url])->findOrEmpty();
            if($collectResult->isEmpty()){
                $collectResult->save([
                    'collect_task_id' => $task->id,
                    'url' => $url,
                    'status' => READY
                ]);
            }
            if($collectResult->status!=SUCCESS){
                $task->save(['status'=>READY]);
            }
        }
    }
    protected function add_collect_task_type3($task){
        $task_id=$task->matching_start;
        $collectResults=CollectResult::where(["collect_task_id"=>$task_id,'status'=>SUCCESS])->select();
        foreach ($collectResults as $collectResult){
            $results=json_decode($collectResult->result,true);
            if(is_array(current($results))){//范围采集任务
                foreach ($results as $result){
                    $url=$result[$task->matching];
                    $collectResult1=CollectResult::where(["collect_task_id"=>$task->id,'url'=>$url])->findOrEmpty();
                    if($collectResult1->isEmpty()){
                        $collectResult1->save([
                            'pid'=>$collectResult->id,
                            'collect_task_id' => $task->id,
                            'url' => $url,
                            'status' => READY
                        ]);
                    }
                }
            }else{//简单采集任务
                $url=$results[$task->matching];
                $collectResult1=CollectResult::where(["collect_task_id"=>$task->id,'url'=>$url])->findOrEmpty();
                if($collectResult1->isEmpty()){
                    $collectResult1->save([
                        'pid'=>$collectResult->id,
                        'collect_task_id' => $task->id,
                        'url' => $url,
                        'status' => READY
                    ]);
                }
            }
        }
        if(!$collectResults->isEmpty()){
            $task->save(['status'=>READY]);
        }
    }
    protected function get_short_result($type,$result){
        if($type==RULE_TYPE_SIMPLE){
            return mb_substr(current($result),0,255);
        }else{
            return mb_substr(current(current($result)),0,255);
        }
    }
}
